#include "gdkdisplay-x11.h"
#include "gdkprivate-x11.h"
#include "xsettings-client.h"
+#include "gdkmonitor-x11.h"
#include <glib.h>
static void gdk_x11_screen_dispose (GObject *object);
static void gdk_x11_screen_finalize (GObject *object);
static void init_randr_support (GdkScreen *screen);
-static void deinit_multihead (GdkScreen *screen);
enum
{
gulong n_atoms;
};
-struct _GdkX11Monitor
-{
- GdkRectangle geometry;
- XID output;
- int width_mm;
- int height_mm;
- char * output_name;
- char * manufacturer;
-};
-
-
static void
gdk_x11_screen_init (GdkX11Screen *screen)
{
g_free (x11_screen->window_manager_name);
- deinit_multihead (GDK_SCREEN (object));
-
G_OBJECT_CLASS (gdk_x11_screen_parent_class)->finalize (object);
}
-static gint
-gdk_x11_screen_get_n_monitors (GdkScreen *screen)
-{
- return GDK_X11_SCREEN (screen)->n_monitors;
-}
-
-static gint
-gdk_x11_screen_get_primary_monitor (GdkScreen *screen)
-{
- return GDK_X11_SCREEN (screen)->primary_monitor;
-}
-
-static gint
-gdk_x11_screen_get_monitor_width_mm (GdkScreen *screen,
- gint monitor_num)
-{
- GdkX11Screen *x11_screen = GDK_X11_SCREEN (screen);
-
- return x11_screen->monitors[monitor_num].width_mm;
-}
-
-static gint
-gdk_x11_screen_get_monitor_height_mm (GdkScreen *screen,
- gint monitor_num)
-{
- GdkX11Screen *x11_screen = GDK_X11_SCREEN (screen);
-
- return x11_screen->monitors[monitor_num].height_mm;
-}
-
-static gchar *
-gdk_x11_screen_get_monitor_plug_name (GdkScreen *screen,
- gint monitor_num)
-{
- GdkX11Screen *x11_screen = GDK_X11_SCREEN (screen);
-
- return g_strdup (x11_screen->monitors[monitor_num].output_name);
-}
-
/**
* gdk_x11_screen_get_monitor_output:
* @screen: (type GdkX11Screen): a #GdkScreen
gint monitor_num)
{
GdkX11Screen *x11_screen = GDK_X11_SCREEN (screen);
+ GdkX11Display *x11_display = GDK_X11_DISPLAY (x11_screen->display);
+ GdkX11Monitor *monitor;
g_return_val_if_fail (GDK_IS_SCREEN (screen), None);
g_return_val_if_fail (monitor_num >= 0, None);
- g_return_val_if_fail (monitor_num < x11_screen->n_monitors, None);
+ g_return_val_if_fail (monitor_num < x11_display->monitors->len, None);
- return x11_screen->monitors[monitor_num].output;
-}
-
-static void
-gdk_x11_screen_get_monitor_geometry (GdkScreen *screen,
- gint monitor_num,
- GdkRectangle *dest)
-{
- GdkX11Screen *x11_screen = GDK_X11_SCREEN (screen);
-
- if (dest)
- {
- *dest = x11_screen->monitors[monitor_num].geometry;
- dest->x /= x11_screen->window_scale;
- dest->y /= x11_screen->window_scale;
- dest->width /= x11_screen->window_scale;
- dest->height /= x11_screen->window_scale;
- }
+ monitor = x11_display->monitors->pdata[monitor_num];
+ return monitor->output;
}
static int
return workspace;
}
-static void
-get_work_area (GdkScreen *screen,
- GdkRectangle *area)
+void
+gdk_x11_screen_get_work_area (GdkScreen *screen,
+ GdkRectangle *area)
{
GdkX11Screen *x11_screen = GDK_X11_SCREEN (screen);
Atom workarea;
XFree (ret_workarea);
}
-static gboolean
-gdk_x11_screen_monitor_has_fullscreen_window (GdkScreen *screen,
- gint monitor)
-{
- GList *toplevels, *l;
- GdkWindow *window;
- gboolean has_fullscreen;
-
- toplevels = gdk_screen_get_toplevel_windows (screen);
-
- has_fullscreen = FALSE;
-
- for (l = toplevels; l; l = l->next)
- {
- window = l->data;
-
- if ((gdk_window_get_state (window) & GDK_WINDOW_STATE_FULLSCREEN) == 0)
- continue;
-
- if (gdk_window_get_fullscreen_mode (window) == GDK_FULLSCREEN_ON_ALL_MONITORS ||
- gdk_screen_get_monitor_at_window (screen, window) == monitor)
- {
- has_fullscreen = TRUE;
- break;
- }
- }
-
- g_list_free (toplevels);
-
- return has_fullscreen;
-}
-
-static void
-gdk_x11_screen_get_monitor_workarea (GdkScreen *screen,
- gint monitor_num,
- GdkRectangle *dest)
-{
- GdkRectangle workarea;
-
- gdk_x11_screen_get_monitor_geometry (screen, monitor_num, dest);
-
- /* The EWMH constrains workarea to be a rectangle, so it
- * can't adequately deal with L-shaped monitor arrangements.
- * As a workaround, we ignore the workarea for anything
- * but the primary monitor. Since that is where the 'desktop
- * chrome' usually lives, this works ok in practice.
- */
- if (monitor_num == GDK_X11_SCREEN (screen)->primary_monitor &&
- !gdk_x11_screen_monitor_has_fullscreen_window (screen, monitor_num))
- {
- get_work_area (screen, &workarea);
- if (gdk_rectangle_intersect (dest, &workarea, &workarea))
- *dest = workarea;
- }
-}
-
-static gint
-gdk_x11_screen_get_monitor_scale_factor (GdkScreen *screen,
- gint monitor_num)
-{
- GdkX11Screen *screen_x11 = GDK_X11_SCREEN (screen);
-
- return screen_x11->window_scale;
-}
-
static GdkVisual *
gdk_x11_screen_get_rgba_visual (GdkScreen *screen)
{
return xwindow != None;
}
-static void
-init_monitor_geometry (GdkX11Monitor *monitor,
- int x, int y, int width, int height)
-{
- monitor->geometry.x = x;
- monitor->geometry.y = y;
- monitor->geometry.width = width;
- monitor->geometry.height = height;
-
- monitor->output = None;
- monitor->width_mm = -1;
- monitor->height_mm = -1;
- monitor->output_name = NULL;
- monitor->manufacturer = NULL;
-}
-
-static void
-free_monitors (GdkX11Monitor *monitors,
- gint n_monitors)
+static GdkX11Monitor *
+find_monitor_by_output (GdkX11Display *x11_display, RROutput output)
{
int i;
- for (i = 0; i < n_monitors; ++i)
+ for (i = 0; i < x11_display->monitors->len; i++)
{
- g_free (monitors[i].output_name);
- g_free (monitors[i].manufacturer);
+ GdkX11Monitor *monitor = x11_display->monitors->pdata[i];
+ if (monitor->output == output)
+ return monitor;
}
- g_free (monitors);
+ return NULL;
}
-#ifdef HAVE_RANDR
-static int
-monitor_compare_function (GdkX11Monitor *monitor1,
- GdkX11Monitor *monitor2)
+static GdkSubpixelLayout
+translate_subpixel_order (int subpixel)
{
- /* Sort the leftmost/topmost monitors first.
- * For "cloned" monitors, sort the bigger ones first
- * (giving preference to taller monitors over wider
- * monitors)
- */
-
- if (monitor1->geometry.x != monitor2->geometry.x)
- return monitor1->geometry.x - monitor2->geometry.x;
-
- if (monitor1->geometry.y != monitor2->geometry.y)
- return monitor1->geometry.y - monitor2->geometry.y;
-
- if (monitor1->geometry.height != monitor2->geometry.height)
- return - (monitor1->geometry.height - monitor2->geometry.height);
-
- if (monitor1->geometry.width != monitor2->geometry.width)
- return - (monitor1->geometry.width - monitor2->geometry.width);
-
- return 0;
+ switch (subpixel)
+ {
+ case 1: return GDK_SUBPIXEL_LAYOUT_HORIZONTAL_RGB;
+ case 2: return GDK_SUBPIXEL_LAYOUT_HORIZONTAL_BGR;
+ case 3: return GDK_SUBPIXEL_LAYOUT_VERTICAL_RGB;
+ case 4: return GDK_SUBPIXEL_LAYOUT_VERTICAL_BGR;
+ case 5: return GDK_SUBPIXEL_LAYOUT_NONE;
+ default: return GDK_SUBPIXEL_LAYOUT_UNKNOWN;
+ }
}
-#endif
static gboolean
-init_randr15 (GdkScreen *screen)
+init_randr15 (GdkScreen *screen, gboolean *changed)
{
#ifdef HAVE_RANDR15
GdkDisplay *display = gdk_screen_get_display (screen);
- GdkX11Display *display_x11 = GDK_X11_DISPLAY (display);
+ GdkX11Display *x11_display = GDK_X11_DISPLAY (display);
GdkX11Screen *x11_screen = GDK_X11_SCREEN (screen);
XRRScreenResources *resources;
RROutput primary_output = None;
RROutput first_output = None;
int i;
- GArray *monitors;
gboolean randr12_compat = FALSE;
XRRMonitorInfo *rr_monitors;
int num_rr_monitors;
+ int old_primary;
- if (!display_x11->have_randr15)
+ if (!x11_display->have_randr15)
return FALSE;
resources = XRRGetScreenResourcesCurrent (x11_screen->xdisplay,
if (!rr_monitors)
return FALSE;
- monitors = g_array_sized_new (FALSE, TRUE, sizeof (GdkX11Monitor), num_rr_monitors);
+ for (i = 0; i < x11_display->monitors->len; i++)
+ {
+ GdkX11Monitor *monitor = x11_display->monitors->pdata[i];
+ monitor->add = FALSE;
+ monitor->remove = TRUE;
+ }
for (i = 0; i < num_rr_monitors; i++)
{
RROutput output = rr_monitors[i].outputs[0];
XRROutputInfo *output_info;
- GdkX11Monitor monitor;
+ GdkX11Monitor *monitor;
+ GdkRectangle geometry;
+ GdkRectangle newgeo;
+ char *name;
+ int refresh_rate = 0;
gdk_x11_display_error_trap_push (display);
output_info = XRRGetOutputInfo (x11_screen->xdisplay, resources, output);
if (first_output == None)
first_output = output;
- init_monitor_geometry (&monitor,
- rr_monitors[i].x,
- rr_monitors[i].y,
- rr_monitors[i].width,
- rr_monitors[i].height);
+ if (output_info->crtc)
+ {
+ XRRCrtcInfo *crtc = XRRGetCrtcInfo (x11_screen->xdisplay, resources, output_info->crtc);
+ int j;
+
+ for (j = 0; j < resources->nmode; j++)
+ {
+ XRRModeInfo *xmode = &resources->modes[j];
+ if (xmode->id == crtc->mode)
+ {
+ refresh_rate = (1000 * xmode->dotClock) / (xmode->hTotal *xmode->vTotal);
+ break;
+ }
+ }
+
+ XRRFreeCrtcInfo (crtc);
+ }
+
+ monitor = find_monitor_by_output (x11_display, output);
+ if (monitor)
+ monitor->remove = FALSE;
+ else
+ {
+ monitor = g_object_new (GDK_TYPE_X11_MONITOR,
+ "display", display,
+ NULL);
+ monitor->output = output;
+ monitor->add = TRUE;
+ g_ptr_array_add (x11_display->monitors, monitor);
+ }
- monitor.width_mm = rr_monitors[i].mwidth;
- monitor.height_mm = rr_monitors[i].mheight;
- monitor.output = output;
- monitor.output_name = g_strndup (output_info->name, output_info->nameLen);
+ gdk_monitor_get_geometry (GDK_MONITOR (monitor), &geometry);
+ name = g_strndup (output_info->name, output_info->nameLen);
+
+ newgeo.x = rr_monitors[i].x / x11_screen->window_scale;
+ newgeo.y = rr_monitors[i].y / x11_screen->window_scale;
+ newgeo.width = rr_monitors[i].width / x11_screen->window_scale;
+ newgeo.height = rr_monitors[i].height / x11_screen->window_scale;
+ if (newgeo.x != geometry.x ||
+ newgeo.y != geometry.y ||
+ newgeo.width != geometry.width ||
+ newgeo.height != geometry.height ||
+ rr_monitors[i].mwidth != gdk_monitor_get_width_mm (GDK_MONITOR (monitor)) ||
+ rr_monitors[i].mheight != gdk_monitor_get_height_mm (GDK_MONITOR (monitor)) ||
+ g_strcmp0 (name, gdk_monitor_get_model (GDK_MONITOR (monitor))))
+ *changed = TRUE;
+
+ gdk_monitor_set_position (GDK_MONITOR (monitor), newgeo.x, newgeo.y);
+ gdk_monitor_set_size (GDK_MONITOR (monitor), newgeo.width, newgeo.height);
+ g_object_notify (G_OBJECT (monitor), "workarea");
+ gdk_monitor_set_physical_size (GDK_MONITOR (monitor),
+ rr_monitors[i].mwidth,
+ rr_monitors[i].mheight);
+ gdk_monitor_set_subpixel_layout (GDK_MONITOR (monitor),
+ translate_subpixel_order (output_info->subpixel_order));
+ gdk_monitor_set_refresh_rate (GDK_MONITOR (monitor), refresh_rate);
+ gdk_monitor_set_scale_factor (GDK_MONITOR (monitor), x11_screen->window_scale);
+ gdk_monitor_set_model (GDK_MONITOR (monitor), name);
+ g_free (name);
if (rr_monitors[i].primary)
- primary_output = monitor.output;
+ primary_output = monitor->output;
- g_array_append_val (monitors, monitor);
XRRFreeOutputInfo (output_info);
}
/* non RandR 1.2+ X driver doesn't return any usable multihead data */
if (randr12_compat)
{
- guint n_monitors = monitors->len;
-
- free_monitors ((GdkX11Monitor *)g_array_free (monitors, FALSE), n_monitors);
+ for (i = 0; i < x11_display->monitors->len; i++)
+ {
+ GdkX11Monitor *monitor = x11_display->monitors->pdata[i];
+ if (monitor->remove)
+ gdk_display_monitor_removed (display, GDK_MONITOR (monitor));
+ }
+ g_ptr_array_remove_range (x11_display->monitors, 0, x11_display->monitors->len);
return FALSE;
}
- g_array_sort (monitors, (GCompareFunc) monitor_compare_function);
-
- x11_screen->n_monitors = monitors->len;
- x11_screen->monitors = (GdkX11Monitor *) g_array_free (monitors, FALSE);
-
- x11_screen->primary_monitor = 0;
+ for (i = x11_display->monitors->len - 1; i >= 0; i--)
+ {
+ GdkX11Monitor *monitor = x11_display->monitors->pdata[i];
+ if (monitor->add)
+ {
+ gdk_display_monitor_added (display, GDK_MONITOR (monitor));
+ *changed = TRUE;
+ }
+ else if (monitor->remove)
+ {
+ g_object_ref (monitor);
+ g_ptr_array_remove (x11_display->monitors, monitor);
+ gdk_display_monitor_removed (display, GDK_MONITOR (monitor));
+ g_object_unref (monitor);
+ *changed = TRUE;
+ }
+ }
- for (i = 0; i < x11_screen->n_monitors; ++i)
+ old_primary = x11_display->primary_monitor;
+ x11_display->primary_monitor = 0;
+ for (i = 0; i < x11_display->monitors->len; ++i)
{
- if (x11_screen->monitors[i].output == primary_output)
+ GdkX11Monitor *monitor = x11_display->monitors->pdata[i];
+ if (monitor->output == primary_output)
{
- x11_screen->primary_monitor = i;
+ x11_display->primary_monitor = i;
break;
}
/* No RandR1.3+ available or no primary set, fall back to prefer LVDS as primary if present */
if (primary_output == None &&
- g_ascii_strncasecmp (x11_screen->monitors[i].output_name, "LVDS", 4) == 0)
+ g_ascii_strncasecmp (gdk_monitor_get_model (GDK_MONITOR (monitor)), "LVDS", 4) == 0)
{
- x11_screen->primary_monitor = i;
+ x11_display->primary_monitor = i;
break;
}
/* No primary specified and no LVDS found */
- if (x11_screen->monitors[i].output == first_output)
- x11_screen->primary_monitor = i;
+ if (monitor->output == first_output)
+ x11_display->primary_monitor = i;
}
- return x11_screen->n_monitors > 0;
+ if (x11_display->primary_monitor != old_primary)
+ *changed = TRUE;
+
+ return x11_display->monitors->len > 0;
#endif
return FALSE;
}
static gboolean
-init_randr13 (GdkScreen *screen)
+init_randr13 (GdkScreen *screen, gboolean *changed)
{
#ifdef HAVE_RANDR
GdkDisplay *display = gdk_screen_get_display (screen);
- GdkX11Display *display_x11 = GDK_X11_DISPLAY (display);
+ GdkX11Display *x11_display = GDK_X11_DISPLAY (display);
GdkX11Screen *x11_screen = GDK_X11_SCREEN (screen);
XRRScreenResources *resources;
RROutput primary_output = None;
RROutput first_output = None;
int i;
- GArray *monitors;
gboolean randr12_compat = FALSE;
+ int old_primary;
- if (!display_x11->have_randr13)
+ if (!x11_display->have_randr13)
return FALSE;
resources = XRRGetScreenResourcesCurrent (x11_screen->xdisplay,
if (!resources)
return FALSE;
- monitors = g_array_sized_new (FALSE, TRUE, sizeof (GdkX11Monitor), resources->noutput);
+ for (i = 0; i < x11_display->monitors->len; i++)
+ {
+ GdkX11Monitor *monitor = x11_display->monitors->pdata[i];
+ monitor->add = FALSE;
+ monitor->remove = TRUE;
+ }
for (i = 0; i < resources->noutput; ++i)
{
if (output_info->crtc)
{
- GdkX11Monitor monitor;
+ GdkX11Monitor *monitor;
XRRCrtcInfo *crtc = XRRGetCrtcInfo (x11_screen->xdisplay, resources, output_info->crtc);
+ char *name;
+ GdkRectangle geometry;
+ GdkRectangle newgeo;
+ int j;
+ int refresh_rate = 0;
- init_monitor_geometry (&monitor, crtc->x, crtc->y, crtc->width, crtc->height);
- monitor.output = output;
- monitor.width_mm = output_info->mm_width;
- monitor.height_mm = output_info->mm_height;
- monitor.output_name = g_strndup (output_info->name, output_info->nameLen);
+ for (j = 0; j < resources->nmode; j++)
+ {
+ XRRModeInfo *xmode = &resources->modes[j];
+ if (xmode->id == crtc->mode)
+ {
+ refresh_rate = (1000 * xmode->dotClock) / (xmode->hTotal *xmode->vTotal);
+ break;
+ }
+ }
- g_array_append_val (monitors, monitor);
+ monitor = find_monitor_by_output (x11_display, output);
+ if (monitor)
+ monitor->remove = FALSE;
+ else
+ {
+ monitor = g_object_new (gdk_x11_monitor_get_type (),
+ "display", display,
+ NULL);
+ monitor->output = output;
+ monitor->add = TRUE;
+ g_ptr_array_add (x11_display->monitors, monitor);
+ }
+
+ gdk_monitor_get_geometry (GDK_MONITOR (monitor), &geometry);
+ name = g_strndup (output_info->name, output_info->nameLen);
+
+ newgeo.x = crtc->x / x11_screen->window_scale;
+ newgeo.y = crtc->y / x11_screen->window_scale;
+ newgeo.width = crtc->width / x11_screen->window_scale;
+ newgeo.height = crtc->height / x11_screen->window_scale;
+ if (newgeo.x != geometry.x ||
+ newgeo.y != geometry.y ||
+ newgeo.width != geometry.width ||
+ newgeo.height != geometry.height ||
+ output_info->mm_width != gdk_monitor_get_width_mm (GDK_MONITOR (monitor)) ||
+ output_info->mm_height != gdk_monitor_get_height_mm (GDK_MONITOR (monitor)) ||
+ g_strcmp0 (name, gdk_monitor_get_model (GDK_MONITOR (monitor))) != 0)
+ *changed = TRUE;
+
+ gdk_monitor_set_position (GDK_MONITOR (monitor), newgeo.x, newgeo.y);
+ gdk_monitor_set_size (GDK_MONITOR (monitor), newgeo.width, newgeo.height);
+ g_object_notify (G_OBJECT (monitor), "workarea");
+ gdk_monitor_set_physical_size (GDK_MONITOR (monitor),
+ output_info->mm_width,
+ output_info->mm_height);
+ gdk_monitor_set_subpixel_layout (GDK_MONITOR (monitor),
+ translate_subpixel_order (output_info->subpixel_order));
+ gdk_monitor_set_refresh_rate (GDK_MONITOR (monitor), refresh_rate);
+ gdk_monitor_set_scale_factor (GDK_MONITOR (monitor), x11_screen->window_scale);
+ gdk_monitor_set_model (GDK_MONITOR (monitor), name);
+
+ g_free (name);
XRRFreeCrtcInfo (crtc);
}
XRRFreeScreenResources (resources);
- /* non RandR 1.2+ X driver doesn't return any usable multihead data */
if (randr12_compat)
{
- guint n_monitors = monitors->len;
-
- free_monitors ((GdkX11Monitor *)g_array_free (monitors, FALSE), n_monitors);
-
+ for (i = 0; i < x11_display->monitors->len; i++)
+ {
+ GdkX11Monitor *monitor = x11_display->monitors->pdata[i];
+ if (monitor->remove)
+ gdk_display_monitor_removed (display, GDK_MONITOR (monitor));
+ }
+ g_ptr_array_remove_range (x11_display->monitors, 0, x11_display->monitors->len);
return FALSE;
}
- g_array_sort (monitors, (GCompareFunc) monitor_compare_function);
-
- x11_screen->n_monitors = monitors->len;
- x11_screen->monitors = (GdkX11Monitor *)g_array_free (monitors, FALSE);
-
- x11_screen->primary_monitor = 0;
+ for (i = x11_display->monitors->len - 1; i >= 0; i--)
+ {
+ GdkX11Monitor *monitor = x11_display->monitors->pdata[i];
+ if (monitor->add)
+ {
+ gdk_display_monitor_added (display, GDK_MONITOR (monitor));
+ *changed = TRUE;
+ }
+ else if (monitor->remove)
+ {
+ g_object_ref (monitor);
+ g_ptr_array_remove (x11_display->monitors, monitor);
+ gdk_display_monitor_removed (display, GDK_MONITOR (monitor));
+ g_object_unref (monitor);
+ *changed = TRUE;
+ }
+ }
+ old_primary = x11_display->primary_monitor;
+ x11_display->primary_monitor = 0;
primary_output = XRRGetOutputPrimary (x11_screen->xdisplay,
x11_screen->xroot_window);
- for (i = 0; i < x11_screen->n_monitors; ++i)
+ for (i = 0; i < x11_display->monitors->len; ++i)
{
- if (x11_screen->monitors[i].output == primary_output)
+ GdkX11Monitor *monitor = x11_display->monitors->pdata[i];
+ if (monitor->output == primary_output)
{
- x11_screen->primary_monitor = i;
+ x11_display->primary_monitor = i;
break;
}
/* No RandR1.3+ available or no primary set, fall back to prefer LVDS as primary if present */
if (primary_output == None &&
- g_ascii_strncasecmp (x11_screen->monitors[i].output_name, "LVDS", 4) == 0)
+ g_ascii_strncasecmp (gdk_monitor_get_model (GDK_MONITOR (monitor)), "LVDS", 4) == 0)
{
- x11_screen->primary_monitor = i;
+ x11_display->primary_monitor = i;
break;
}
/* No primary specified and no LVDS found */
- if (x11_screen->monitors[i].output == first_output)
- x11_screen->primary_monitor = i;
+ if (monitor->output == first_output)
+ x11_display->primary_monitor = i;
}
- return x11_screen->n_monitors > 0;
+ if (x11_display->primary_monitor != old_primary)
+ *changed = TRUE;
+
+ return x11_display->monitors->len > 0;
#endif
return FALSE;
}
-void
-_gdk_x11_screen_get_edge_monitors (GdkScreen *screen,
- gint *top,
- gint *bottom,
- gint *left,
- gint *right)
+static void
+init_no_multihead (GdkScreen *screen, gboolean *changed)
{
GdkX11Screen *x11_screen = GDK_X11_SCREEN (screen);
- gint top_most_pos = x11_screen->height;
- gint left_most_pos = x11_screen->width;
- gint bottom_most_pos = 0;
- gint right_most_pos = 0;
- gint monitor_num;
+ GdkX11Display *x11_display = GDK_X11_DISPLAY (x11_screen->display);
+ GdkX11Monitor *monitor;
+ GdkRectangle geometry;
+ int i;
- for (monitor_num = 0; monitor_num < x11_screen->n_monitors; monitor_num++)
+ for (i = 0; i < x11_display->monitors->len; i++)
{
- gint monitor_x = x11_screen->monitors[monitor_num].geometry.x;
- gint monitor_y = x11_screen->monitors[monitor_num].geometry.y;
- gint monitor_max_x = monitor_x + x11_screen->monitors[monitor_num].geometry.width;
- gint monitor_max_y = monitor_y + x11_screen->monitors[monitor_num].geometry.height;
-
- if (left && left_most_pos > monitor_x)
- {
- left_most_pos = monitor_x;
- *left = monitor_num;
- }
- if (right && right_most_pos < monitor_max_x)
- {
- right_most_pos = monitor_max_x;
- *right = monitor_num;
- }
- if (top && top_most_pos > monitor_y)
- {
- top_most_pos = monitor_y;
- *top = monitor_num;
- }
- if (bottom && bottom_most_pos < monitor_max_y)
- {
- bottom_most_pos = monitor_max_y;
- *bottom = monitor_num;
- }
+ GdkX11Monitor *monitor = x11_display->monitors->pdata[i];
+ monitor->add = FALSE;
+ monitor->remove = TRUE;
}
-}
-
-static void
-deinit_multihead (GdkScreen *screen)
-{
- GdkX11Screen *x11_screen = GDK_X11_SCREEN (screen);
-
- free_monitors (x11_screen->monitors, x11_screen->n_monitors);
-
- x11_screen->n_monitors = 0;
- x11_screen->monitors = NULL;
-}
-
-static gboolean
-compare_monitor (GdkX11Monitor *m1,
- GdkX11Monitor *m2)
-{
- if (m1->geometry.x != m2->geometry.x ||
- m1->geometry.y != m2->geometry.y ||
- m1->geometry.width != m2->geometry.width ||
- m1->geometry.height != m2->geometry.height)
- return FALSE;
-
- if (m1->width_mm != m2->width_mm ||
- m1->height_mm != m2->height_mm)
- return FALSE;
-
- if (g_strcmp0 (m1->output_name, m2->output_name) != 0)
- return FALSE;
- if (g_strcmp0 (m1->manufacturer, m2->manufacturer) != 0)
- return FALSE;
-
- return TRUE;
-}
-
-static gboolean
-compare_monitors (GdkX11Monitor *monitors1, gint n_monitors1,
- GdkX11Monitor *monitors2, gint n_monitors2)
-{
- gint i;
-
- if (n_monitors1 != n_monitors2)
- return FALSE;
-
- for (i = 0; i < n_monitors1; i++)
+ monitor = find_monitor_by_output (x11_display, 0);
+ if (monitor)
+ monitor->remove = FALSE;
+ else
{
- if (!compare_monitor (monitors1 + i, monitors2 + i))
- return FALSE;
+ monitor = g_object_new (gdk_x11_monitor_get_type (),
+ "display", x11_display,
+ NULL);
+ monitor->output = 0;
+ monitor->add = TRUE;
+ g_ptr_array_add (x11_display->monitors, monitor);
}
- return TRUE;
-}
-
-static void
-init_no_multihead (GdkScreen *screen)
-{
- GdkX11Screen *x11_screen = GDK_X11_SCREEN (screen);
-
- x11_screen->n_monitors = 1;
- x11_screen->monitors = g_new0 (GdkX11Monitor, 1);
- x11_screen->primary_monitor = 0;
-
- init_monitor_geometry (x11_screen->monitors, 0, 0,
- WidthOfScreen (x11_screen->xscreen),
- HeightOfScreen (x11_screen->xscreen));
+ gdk_monitor_get_geometry (GDK_MONITOR (monitor), &geometry);
+ if (0 != geometry.x ||
+ 0 != geometry.y ||
+ gdk_screen_get_width (screen) != geometry.width ||
+ gdk_screen_get_height (screen) != geometry.height ||
+ gdk_screen_get_width_mm (screen) != gdk_monitor_get_width_mm (GDK_MONITOR (monitor)) ||
+ gdk_screen_get_height_mm (screen) != gdk_monitor_get_height_mm (GDK_MONITOR (monitor)))
+ *changed = TRUE;
+
+ gdk_monitor_set_position (GDK_MONITOR (monitor), 0, 0);
+ gdk_monitor_set_size (GDK_MONITOR (monitor),
+ gdk_screen_get_width (screen),
+ gdk_screen_get_height (screen));
+ g_object_notify (G_OBJECT (monitor), "workarea");
+ gdk_monitor_set_physical_size (GDK_MONITOR (monitor),
+ gdk_screen_get_height_mm (screen),
+ gdk_screen_get_height_mm (screen));
+ gdk_monitor_set_scale_factor (GDK_MONITOR (monitor), x11_screen->window_scale);
+
+ if (x11_display->primary_monitor != 0)
+ *changed = TRUE;
+ x11_display->primary_monitor = 0;
+
+ for (i = x11_display->monitors->len - 1; i >= 0; i--)
+ {
+ GdkX11Monitor *monitor = x11_display->monitors->pdata[i];
+ if (monitor->add)
+ {
+ gdk_display_monitor_added (GDK_DISPLAY (x11_display), GDK_MONITOR (monitor));
+ *changed = TRUE;
+ }
+ else if (monitor->remove)
+ {
+ g_object_ref (monitor);
+ g_ptr_array_remove (x11_display->monitors, monitor);
+ gdk_display_monitor_removed (GDK_DISPLAY (x11_display), GDK_MONITOR (monitor));
+ g_object_unref (monitor);
+ *changed = TRUE;
+ }
+ }
}
-static void
+static gboolean
init_multihead (GdkScreen *screen)
{
- if (init_randr15 (screen))
- return;
+ gboolean any_changed = FALSE;
- if (init_randr13 (screen))
- return;
+ if (!init_randr15 (screen, &any_changed) &&
+ !init_randr13 (screen, &any_changed))
+ init_no_multihead (screen, &any_changed);
- init_no_multihead (screen);
+ return any_changed;
}
static void
update_bounding_box (GdkScreen *screen)
{
GdkX11Screen *x11_screen = GDK_X11_SCREEN (screen);
+ GdkX11Display *x11_display = GDK_X11_DISPLAY (x11_screen->display);
gint i, x1, y1, x2, y2;
x1 = y1 = G_MAXINT;
x2 = y2 = G_MININT;
- for (i = 0; i < x11_screen->n_monitors; i++)
+ for (i = 0; i < x11_display->monitors->len; i++)
{
- GdkX11Monitor *monitor;
-
- monitor = &x11_screen->monitors[i];
- x1 = MIN (x1, monitor->geometry.x);
- y1 = MIN (y1, monitor->geometry.y);
- x2 = MAX (x2, monitor->geometry.x + monitor->geometry.width);
- y2 = MAX (y2, monitor->geometry.y + monitor->geometry.height);
+ GdkX11Monitor *monitor = x11_display->monitors->pdata[i];
+ GdkRectangle geometry;
+
+ gdk_monitor_get_geometry (GDK_MONITOR (monitor), &geometry);
+ x1 = MIN (x1, geometry.x);
+ y1 = MIN (y1, geometry.y);
+ x2 = MAX (x2, geometry.x + geometry.width);
+ y2 = MAX (y2, geometry.y + geometry.height);
}
x11_screen->width = x2 - x1;
else
x11_screen->window_scale = 1;
- init_multihead (screen);
init_randr_support (screen);
-
+ init_multihead (screen);
+
_gdk_x11_screen_init_visuals (screen);
_gdk_x11_screen_init_root_window (screen);
update_bounding_box (screen);
_gdk_x11_screen_set_window_scale (GdkX11Screen *x11_screen,
gint scale)
{
+ GdkX11Display *x11_display = GDK_X11_DISPLAY (x11_screen->display);
GList *toplevels, *l;
GdkWindow *root;
+ int i;
if (x11_screen->window_scale == scale)
return;
_gdk_x11_window_set_window_scale (window, scale);
}
+ for (i = 0; i < x11_display->monitors->len; i++)
+ {
+ GdkMonitor *monitor = GDK_MONITOR (x11_display->monitors->pdata[i]);
+
+ gdk_monitor_set_scale_factor (monitor, scale);
+ }
+
g_signal_emit_by_name (GDK_SCREEN (x11_screen), "monitors-changed");
}
static void
process_monitors_change (GdkScreen *screen)
{
- GdkX11Screen *x11_screen = GDK_X11_SCREEN (screen);
- gint n_monitors;
- gint primary_monitor;
- GdkX11Monitor *monitors;
- gboolean changed;
-
- primary_monitor = x11_screen->primary_monitor;
- n_monitors = x11_screen->n_monitors;
- monitors = x11_screen->monitors;
-
- x11_screen->n_monitors = 0;
- x11_screen->monitors = NULL;
-
- init_multihead (screen);
-
- changed =
- !compare_monitors (monitors, n_monitors,
- x11_screen->monitors, x11_screen->n_monitors) ||
- x11_screen->primary_monitor != primary_monitor;
-
- free_monitors (monitors, n_monitors);
-
- if (changed)
+ if (init_multihead (screen))
{
update_bounding_box (screen);
g_signal_emit_by_name (screen, "monitors-changed");
g_signal_emit_by_name (screen, "size-changed");
}
+void
+_gdk_x11_screen_get_edge_monitors (GdkScreen *screen,
+ gint *top,
+ gint *bottom,
+ gint *left,
+ gint *right)
+{
+ GdkX11Screen *x11_screen = GDK_X11_SCREEN (screen);
+ gint top_most_pos = x11_screen->height;
+ gint left_most_pos = x11_screen->width;
+ gint bottom_most_pos = 0;
+ gint right_most_pos = 0;
+ gint i;
+
+ for (i = 0; i < x11_screen->monitors->len; i++)
+ {
+ GdkMonitor *monitor = x11_screen->monitors->pdata[i];
+ GdkRectangle geometry;
+
+ gdk_monitor_get_geometry (monitor, &geometry);
+
+ if (left && left_most_pos > geometry.x)
+ {
+ left_most_pos = geometry.x;
+ *left = i;
+ }
+ if (right && right_most_pos < geometry.x + geometry.width)
+ {
+ right_most_pos = geometry.x + geometry.width;
+ *right = i;
+ }
+ if (top && top_most_pos > geometry.y)
+ {
+ top_most_pos = geometry.y;
+ *top = i;
+ }
+ if (bottom && bottom_most_pos < geometry.y + geometry.height)
+ {
+ bottom_most_pos = geometry.y + geometry.height;
+ *bottom = i;
+ }
+ }
+}
+
void
_gdk_x11_screen_window_manager_changed (GdkScreen *screen)
{
screen_class->get_height_mm = gdk_x11_screen_get_height_mm;
screen_class->get_number = gdk_x11_screen_get_number;
screen_class->get_root_window = gdk_x11_screen_get_root_window;
- screen_class->get_n_monitors = gdk_x11_screen_get_n_monitors;
- screen_class->get_primary_monitor = gdk_x11_screen_get_primary_monitor;
- screen_class->get_monitor_width_mm = gdk_x11_screen_get_monitor_width_mm;
- screen_class->get_monitor_height_mm = gdk_x11_screen_get_monitor_height_mm;
- screen_class->get_monitor_plug_name = gdk_x11_screen_get_monitor_plug_name;
- screen_class->get_monitor_geometry = gdk_x11_screen_get_monitor_geometry;
- screen_class->get_monitor_workarea = gdk_x11_screen_get_monitor_workarea;
- screen_class->get_monitor_scale_factor = gdk_x11_screen_get_monitor_scale_factor;
screen_class->get_system_visual = _gdk_x11_screen_get_system_visual;
screen_class->get_rgba_visual = gdk_x11_screen_get_rgba_visual;
screen_class->is_composited = gdk_x11_screen_is_composited;